package liquidfs.core;

import java.io.*;

import utility.*;

import liquidfs.*;
import liquidfs.data.*;
import liquidfs.data.ex.*;
import liquidfs.data.fs.*;
import liquidfs.data.ops.*;
import liquidfs.ui.net.*;

public class LiquidFileSystem {

   private Application app;
   private Configuration config;
   private OperationProcessor processor;
   
   public LiquidFileSystem (Application app) {
      this.app = app;
      this.config = app.getConfiguration();
      this.processor = app.getOperationProcessor();
   }
   
   public Configuration getConfiguration () {
      return this.config;
   }
   
   public LocalLiquidDirectory getRoot () {
      return new LocalLiquidDirectory(this, "/");
   }
   
   public PeerDevice getLocalDevice () {
      return config.getLocalDevice();
   }
   
   public LiquidObject getPath (String path) {
      
      File file = this.getLocalFile(path);
      
      if (file.exists()) {
         if (file.isDirectory()) {
            return new LocalLiquidDirectory(this, path);
         }
         else {
            return new LocalLiquidFile(this, path);
         }
      }
      else {
         return new RemoteLiquidObject(this, path);
      }
   }
   
   public boolean isLocal (String path) {
      File file = this.getLocalFile(path);
      return file.exists();      
   }
   
   public Metadata getMetadata (String path) {
      return this.app.getMetadatabase().getMetadata(path);
   }
   
   public void setMetadata (String path, Metadata metadata) {
      this.app.getMetadatabase().setMetadata(path, metadata);
   }
   
   public File getLocalFile (String path) {
      return new File(this.getLocalPath(path));
   }
   
   private String getLocalPath (String path) {
      return config.getBackendFiles() + path;
   }

   public<T> Result<T> process(Operation<T> op) {
      return this.process(op, null, null);
   }
   
   public<T> Result<T> process(Operation<T> op, InputStream in, OutputStream out) {
      Result<T> result = processor.process(op, in, out);
      return result;
   }
   
   public<T> Result<T> relay (Link link, Operation<T> op) {
      return this.relay(link, op, null, null);
   }
   
   public<T> Result<T> relay (Link link, Operation<T> op, InputStream in, OutputStream out) {
      Result<T> result = processor.relay(link, op, in, out);
      return result;
   }
   
}
